package com.example.musicdemo.widget

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.example.musicdemo.R
import com.example.musicdemo.model.LyricBean
import com.example.musicdemo.util.LyricLoader
import com.example.musicdemo.util.LyricUtil
import kotlinx.android.synthetic.main.activity_music_player_bottom.view.*
import org.jetbrains.anko.doAsync

class LyricView : View {
    val mPaint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG)
    }
    private val mList by lazy { ArrayList<LyricBean>() }
    var mCenterLine = 0
    var mViewW: Int = 0
    var mViewH: Int = 0
    var mBigSize = 0f
    var mSmallSize = 0f
    var mWhite = 0
    var mGreen = 0
    var mLineHeight = 0
    var mDuration = 0
    var mProgress = 0
    var mUpdateByPro = true//指定是否可以通过progress进度更新歌词  默认true
    var mDownY = 0f
    var mMarkY = 0f
    var mOffsetY = 0f

    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

    init {
        mBigSize = resources.getDimension(R.dimen.bigSize)
        mSmallSize = resources.getDimension(R.dimen.smallSize)
        mWhite = resources.getColor(R.color.white)
        mGreen = resources.getColor(R.color.green)
        mLineHeight = resources.getDimensionPixelOffset(R.dimen.lineHeight)
        //画笔
        mPaint.textAlign = Paint.Align.CENTER//在x方向确定位置是通过中间位置确定坐标

    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (mList.size == 0) {
            drawSingleLine(canvas)
        } else {
            draManyLine(canvas)
        }
    }

    private fun drawSingleLine(canvas: Canvas?) {
        //初始化pint颜色和大小
        mPaint.textSize = mBigSize
        mPaint.color = mGreen
        val text = "正在加载歌词"
        //求文本的宽度和高度
        val bounds = Rect()
        mPaint.getTextBounds(text, 0, text.length, bounds)
        val textW = bounds.width()
        val textH = bounds.height()
        val y = mViewH / 2 + textH / 2
        //绘制
        canvas?.drawText(text, mViewW / 2.toFloat(), y.toFloat(), mPaint)
    }


    /**
     * 布局之后执行
     */
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mViewW = w
        mViewH = h
    }

    private fun draManyLine(canvas: Canvas?) {
        if (mUpdateByPro) {
            //求居中行偏移y
            var lineTime = 0
            //最后一行居中
            if (mCenterLine == mList.size - 1) {
                lineTime = mDuration - mList.get(mCenterLine).startTime
            } else {
                //其他行居中。行的可用时间 = 下一行开始时间- 居中行开始时间
                val centerS = mList[mCenterLine].startTime
                val nextS = mList[mCenterLine + 1].startTime
                lineTime = nextS - centerS
            }
            //偏移时间 = progress - 居中行开始时间
            val offsetTime = mProgress - mList[mCenterLine].startTime
            //        偏移百分比 = 偏移时间/行可用时间
            val offsetPercent = offsetTime / (lineTime.toFloat())
            //        偏移y = 偏移百分比*行高
            mOffsetY = offsetPercent * mLineHeight
        }
        val centerText = mList.get(mCenterLine).content
        val bounds = Rect()
        mPaint.getTextBounds(centerText, 0, centerText.length, bounds)
        val textH = bounds.height()
        //居中行y
        val centerY = mViewH / 2 + textH / 2 - mOffsetY
        for ((index, value) in mList.withIndex()) {
            if (index == mCenterLine) {
                //绘制居中行
                mPaint.color = mWhite
                mPaint.textSize = mBigSize
            } else {
                //绘制其他行
                mPaint.color = mGreen
                mPaint.textSize = mSmallSize

            }
            val curX = mViewW / 2
            val curY = centerY + (index - mCenterLine) * mLineHeight
            //边界处理
            if (curY < 0) continue
            if (curY > mViewH + mLineHeight) break
            val curText = mList[index].content
            canvas?.drawText(curText, curX.toFloat(), curY.toFloat(), mPaint)

        }
    }


    fun updateProgress(progress: Int) {
        if (!mUpdateByPro) return
        if (mList.size == 0) return
        this.mProgress = progress
        //获取居中行行号
        //先判断居中行是否是最后一行
        if (progress >= mList[mList.size - 1].startTime) {
            mCenterLine = mList.size - 1
        } else {
            //其他行居中 循环遍历集合
            for (index in 0 until mList.size - 1) {
                //progress>=当前行开始时间和progress《下一行开始时间
                val curStartTime = mList[index].startTime
                val nextStartTime = mList[index + 1].startTime
                if (progress in curStartTime until nextStartTime) {
                    mCenterLine = index
                    break
                }
            }
        }
        invalidate()
    }

    /**
     * 设置当前 播放歌曲总时长
     */
    fun setSongDuration(duration: Int) {
        this.mDuration = duration
    }

    /**
     * 设置歌曲播放名称
     * 解析歌词文件添加到集合中
     */
    fun setSongName(name: String?) {
        doAsync {
            this@LyricView.mList.clear()
            this@LyricView.mList.addAll(LyricUtil.parseLyric(LyricLoader.loadLyricFile(name)))
        }
    }


    /**
     * 歌词空间手势事件的处理
     * 1 手指按下的时候，停止通过进度更新歌曲
     */
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        event?.let {
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    //停止通过进度更新歌曲
                    mUpdateByPro = false
                    //记录手指按下的y
                    mDownY = event.y
                    //记录原来进度已经更新y
                    mMarkY = this.mOffsetY
                }
                MotionEvent.ACTION_MOVE -> {
                    //当前y
                    val endY = event.y
                    //求手指移动y
                    val offY = mDownY - endY
                    //重新设居中行偏移
                    this.mOffsetY = offY + mMarkY
                    //如果最终的y的偏移大于行高，重新确定居中行
                    if (Math.abs(this.mOffsetY) > mLineHeight) {
                        //求居中行行号偏移
                        val offsetLine = (this.mOffsetY / mLineHeight).toInt()
                        mCenterLine += offsetLine
                        //对居中行做边界处理
                        if (mCenterLine < 0) mCenterLine =
                            0 else if (mCenterLine > mList.size - 1) mCenterLine = mList.size - 1
                        //downY重新设置
                        this.mDownY = endY
                        //重新确定偏移y
                        this.mOffsetY = this.mOffsetY % mLineHeight
                        //重新确定偏移y
                        this.mOffsetY = this.mOffsetY % mLineHeight
                        //重新记录y的偏移量
                        mMarkY = this.mOffsetY
                    }
                    invalidate()

                }
                MotionEvent.ACTION_UP -> {
                    mUpdateByPro = true
                    listener?.invoke(mList[mCenterLine].startTime)
                }
            else->{}
            }

        }



        return true

    }

    fun getPlayFlag(): Boolean {
        return mUpdateByPro
    }


    //进度回调函数
    private var listener: ((progress: Int) -> Unit)? = null

    //设置进度回调函数函数
    fun setProgressListener(listener: (progress: Int) -> Unit) {
        this.listener = listener
    }

}